﻿
namespace WekaSharp


open WekaSharp

[<RequireQualifiedAccess>]
module Parameter =

    type AttributeSelection = NoAttributeSelect | M5Select | GreedySelect

    type DistanceWeighting = NoDistanceWeighting | WeightBy1MinusDistance | WeightBy1DivideDistance
    type NNSearchAlgorithm = LinearSearch | BallTree | CoverTree | KDTree
    type DistanceFunction = Euclidean | Chebyshev | EditDistance | Manhattan
        with
        static member GetString(distanceFunction) = 
                let d = match distanceFunction with
                        | Some (v) -> v
                        | None -> DistanceFunction.Euclidean
                match d with
                | DistanceFunction.Euclidean -> "weka.core.EuclideanDistance -R first-last"
                | DistanceFunction.Chebyshev -> "weka.core.ChebyshevDistance -R first-last"
                | DistanceFunction.EditDistance -> "weka.core.EditDistance -R first-last"
                | DistanceFunction.Manhattan -> "weka.core.ManhattanDistance -R first-last"

    type SVMType = Default_CSVC | NuSVC | OneClass | EpsilonSVR | NuSVR
    type SVMKernelType = LinearKernel | PolyKernel | SigmoidKernel | GaussianKernel

    type KNN() = 
        static member DefaultPara = "-K 1 -W 0 -A \"weka.core.neighboursearch.LinearNNSearch -A \\\"weka.core.EuclideanDistance -R first-last\\\"\""
        static member MakePara(?K, ?distanceWeight, ?searchAlgorithm, ?distanceFunction) = 
            let KStr = 
                let k = match K with
                        | Some (v) -> v
                        | None -> 1
                "-K " + k.ToString()
            let distanceWeightStr = 
                let d = match distanceWeight with
                        | Some (v) -> v
                        | None -> DistanceWeighting.NoDistanceWeighting
                match d with
                | DistanceWeighting.NoDistanceWeighting -> ""
                | DistanceWeighting.WeightBy1DivideDistance -> "-I"
                | DistanceWeighting.WeightBy1MinusDistance -> "-F"

            let distanceFunctionStr = DistanceFunction.GetString distanceFunction 

            let searchAlgorithmStr = 
                let s = match searchAlgorithm with
                        | Some (v) -> v
                        | None -> NNSearchAlgorithm.LinearSearch
                match s with
                | NNSearchAlgorithm.LinearSearch -> 
                    "weka.core.neighboursearch.LinearNNSearch" + " -A " + "\"" + distanceFunctionStr + "\""
                | NNSearchAlgorithm.BallTree ->
                    "weka.core.neighboursearch.BallTree" + " -A " + "\"" + distanceFunctionStr + "\""
                | NNSearchAlgorithm.CoverTree ->
                    "weka.core.neighboursearch.CoverTree" + " -A " + "\"" + distanceFunctionStr + "\""
                | NNSearchAlgorithm.KDTree ->
                    "weka.core.neighboursearch.KDTree" + " -A " + "\"" + distanceFunctionStr + "\""

            KStr + " " + distanceWeightStr + " " + searchAlgorithmStr
                

    type J48() =
        static member DefaultPara =  "-C 0.25 -M 2"
        static member MakePara(?binarySplits, ?confidenceFactor, ?minNumObj, ?unpruned, ?useLaplace) =
            let binarySplitsStr = 
                let b = match binarySplits with
                        | Some (v) -> v
                        | None -> false
                if not b then "-B" else ""
            let confidenceFactorStr = 
                let c = match confidenceFactor with
                        | Some (v) -> v
                        | None -> 0.25 // default confi
                "-C " + c.ToString()
            let minNumObjStr = 
                let m = match minNumObj with
                        | Some (v) -> v
                        | None -> 2
                "-M " + m.ToString()
            let unprunedStr = 
                let u = match unpruned with
                        | Some (v) -> v
                        | None -> false
                if u then "-U" else ""
            let useLaplaceStr = 
                let u = match useLaplace with
                        | Some (v) -> v
                        | None -> false
                if u then "-A" else ""
            binarySplitsStr + " " + confidenceFactorStr + " " + minNumObjStr + " " + unprunedStr + " " + useLaplaceStr

        
    type LogReg() =
        static member DefaultPara = "-R 1.0E08 -M -1"
        static member MakePara(?maxIter, ?ridge) = 
            let maxIterStr = 
                let m = match maxIter with
                        | Some (v) -> v
                        | None -> -1
                "-M " + m.ToString()
            let ridgeStr = 
                let r = match ridge with
                        | Some(v) -> v
                        | None -> 1.0E08
                "-R " + r.ToString()
            maxIterStr + " " + ridgeStr

    type NaiveBayes() =
        static member DefaultPara  = ""
        static member MakePara(?discreteRealAttributes) = 
            match discreteRealAttributes with
            | Some (v) when v-> "-D" 
            | Some (_) -> ""
            | None -> ""

    type SVM() =
        static member DefaultPara  = "-S 0 -K 2 -D 3 -G 0.0 -R 0.0 -N 0.5 -M 40.0 -C 1.0 -E 0.0010 -P 0.1"
        static member MakePara(?svmType, ?kernelType, ?C, ?nu, ?coef0, ?gamma, ?degree, ?probOutput) =
            let svmTypeStr = 
                let s = match svmType with
                        | Some (v) -> v
                        | None -> SVMType.Default_CSVC
                match s with 
                | SVMType.Default_CSVC -> "-S 0"
                | SVMType.NuSVC -> "-S 1"
                | SVMType.OneClass -> "-S 2"
                | SVMType.EpsilonSVR -> "-S 3"
                | SVMType.NuSVR -> "-S 4"

            let kernelTypeStr = 
                let k = match kernelType with
                        | Some(v) -> v
                        | None -> SVMKernelType.LinearKernel
                match k with
                | SVMKernelType.LinearKernel -> "-K 0"
                | SVMKernelType.PolyKernel -> "-K 1"
                | SVMKernelType.GaussianKernel -> "-K 2"
                | SVMKernelType.SigmoidKernel -> "-K 3"

            let CStr = 
                let c = match C with
                        | Some (v) -> v
                        | None -> 1.0
                "-C " + c.ToString()

            let nuStr = 
                let n = match nu with
                        | Some (v) -> v
                        | None -> 0.5
                "-N " + n.ToString()

            let coef0Str = 
                let c = match coef0 with
                        | Some (v) -> v
                        | None -> 0.0
                "-R " + c.ToString()

            let degreeStr = 
                let d = match degree with
                        | Some (v) -> v
                        | None -> 3
                "-D " + d.ToString()

            let gammaStr =
                let g = match gamma with
                        | Some (v) -> v
                        | None -> 0.0
                "-G " + g.ToString()

            let probOutputStr = 
                let p = match probOutput with
                        | Some (v) -> v
                        | None -> false
                if p then "-B" else ""

            svmTypeStr + " " + kernelTypeStr + " " + CStr + " " + nuStr + " " + coef0Str + " " + degreeStr + " " + gammaStr + " " + probOutputStr

    type LinReg() = 
        static member DefaultPara = "-S 0 -R 1.0E-8"
        static member MakePara(?ridge, ?attrSelect, ?eliminateColinearAttrs) = 
            let attrSelectStr = 
                let a = match attrSelect with
                        | Some v -> v
                        | None -> AttributeSelection.NoAttributeSelect
                match a with
                    | AttributeSelection.NoAttributeSelect -> "-S 1"
                    | AttributeSelection.M5Select -> "-S 0"
                    | AttributeSelection.GreedySelect -> "-S 2"
            let eliminateColinearAttrsStr = 
                let e = match eliminateColinearAttrs with
                        | Some v -> v
                        | None -> false
                if e then "" else "-C"
            let ridgeStr = 
                let r = match ridge with
                        | Some v -> v
                        | None -> 1.0E-8
                "-R " + r.ToString()
            attrSelectStr + " " + eliminateColinearAttrsStr + " " + ridgeStr


    type KMeans() = 
        static member DefaultPara = "-N 2 -A \"weka.core.EuclideanDistance - R first-last\" -I 500 -S 10"
        static member MakePara(?K, ?maxIter, ?distanceFunction, ?seed) = 
            let KStr = 
                let k = match K with
                        | Some v -> v
                        | None -> 2
                "-N " + k.ToString()
            let maxIterStr = 
                let m = match maxIter with
                        | Some v -> v
                        | None -> 500
                "-I " + m.ToString()

            let distanceFunctionStr = DistanceFunction.GetString distanceFunction

            let seedStr = 
                let s = match seed with
                        | Some v -> v
                        | None -> 10
                "-S " + s.ToString()

            KStr + " " + maxIterStr + " " + distanceFunctionStr + " " + seedStr

                        
    type EM() =
        static member DefaultPara = "-I 100 -N -1 -M 1.0E-6 -S 100"

        static member MakePara(?K, ?maxIter, ?seed) = 
            let KStr = 
                let k = match K with
                        | Some v -> v
                        | None -> 2
                "-N " + k.ToString()
            let maxIterStr = 
                let m = match maxIter with
                        | Some v -> v
                        | None -> 500
                "-I " + m.ToString()

            let seedStr = 
                let s = match seed with
                        | Some v -> v
                        | None -> 10
                "-S " + s.ToString()

            KStr + " " + maxIterStr + " " + seedStr


    // TODO: finish the MakePara method for the following algorithms
    type NeuralNet() =
        static member DefaultPara  = "-L 0.3 -M 0.2 -N 500 -V 0 -S 0 -E 20 -H a"
        static member MakePara(?ToBeAddedMore) = NeuralNet.DefaultPara

    type AdaBoost() =
        static member DefaultPara = "-P 100 -S 1 -I 10 -W weka.classifiers.trees.DecisionStump"
        static member MakePara(?ToBeAddedMore) = AdaBoost.DefaultPara

    type Bagging() = 
        static member DefaultPara = "-P 100 -S 1 -I 10 -W weka.classifiers.trees.REPTree -- -M 2 -V -.0010 -N 3 -S 1 -L -1"
        static member MakePara(?ToBeAddedMore) = Bagging.DefaultPara

    type DBScan() = 
        static member DefaultPara = "-E 0.9 -M 6 -I weka.clusterers.forOPTICSAndDBScan.Databases.SequentialDatabase -D weka.clusterers.forOPTICSAndDBScan.DataObjects.EuclidianDataObject"
        static member MakePara(?ToBeAddedMore) = DBScan.DefaultPara
